package example.lamebdaj;

import dev.ideas.funkyj.function.F;
import dev.ideas.funkyj.group.Group1;
import dev.ideas.funkyj.group.Group2;
import dev.ideas.funkyj.sequence.Sequence;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;

import static dev.ideas.funkyj.sequence.Sequence.*;
import static example.lamebdaj.Lamebdaj.Person.$age;
import static example.lamebdaj.Lamebdaj.Person.$name;
import static org.junit.Assert.assertEquals;

/**
 */
public class Lamebdaj {

    Person toto = new Person("Toto", 35);
    Person titi = new Person("Titi", 29);
    Person tata = new Person("Tata", 39);
    Person tutu = new Person("Tutu", 29);
    List<Person> meAndMyFriends = from(toto, titi, tata, tutu).asList();

    /*Aggregating items or item's values*/
    @Test public void t1() {
        //List<Integer> biggerThan3 = filter(greaterThan(3), asList(1, 2, 3, 4, 5));
        Sequence<Integer> biggerThan3 = from(range(1, 5)).where(biggerThan(3));

        //List<Integer> oddNumbers = filter(odd, asList(1, 2, 3, 4, 5));
        Sequence<Integer> odds = from(range(1, 5)).where(odd);

        //List<Person> oldFriends = filter(having(on(Person.class).getAge(), greaterThan(30)), meAndMyFriends);
        Sequence<Person> oldFriends = from(meAndMyFriends).where($age.is(biggerThan(30)));

        //int sumF = sumF(asList(1, 2, 3, 4, 5));
        int sum15 = from(range(1, 5)).to(sum).get();

        //int totalAge = sumF(meAndMyFriends, on(Person.class).getAge());
        int totalAge = from(meAndMyFriends).sum($age);

        //todo some other options maybe
        int totalAge1 = from(meAndMyFriends).to($age).to(sum).get();
        //int totalAge2 = from(meAndMyFriends).to($age, sumF).get(); //todo ?
        //int totalAge3 = from(meAndMyFriends).to(sumF.of(new )).get(); //todo

        //
        assertEquals(biggerThan3.asList(), from(range(4, 5)).asList());
        assertEquals(odds.asList(), from(1, 3, 5).asList());
        assertEquals(oldFriends.asList(), from(toto, tata).asList());
        assertEquals(15, sum15);
        assertEquals(totalAge, 132);
        assertEquals(totalAge1, 132);
    }

    /*Converting, indexing and sorting items*/
    @Test public void t2() {
        List<String> strings = Arrays.asList("first", "second", "third");

        //List<Integer> lengths = convert(strings, new StringLengthConverter());
        List<Integer> lengths = from(strings).to(length).asList();

        //List<Integer> lengths = convert(strings, new PropertyExtractor("length"));
        List lengths1 = from(strings).to($("count")).asList();

        //List<Integer> ages = extract(persons, on(Person.class).getAge());
        List<Integer> ages = from(meAndMyFriends).to($age).asList();

        //Map<String, Person> personsByName = index(persons, on(Person.class).getFirstName());
        final Group1<String, Person> personsByName = from(meAndMyFriends).groupBy($name);

        //List<Person> sorted = sort(persons, on(Person.class).getAge());
        List<Person> sorted = from(meAndMyFriends).sort($age).asList();

        //
        assertEquals(lengths, from(5, 6, 5).asList());
        assertEquals(lengths1, from(5, 6, 5).asList());
        assertEquals(sorted, from(titi, tutu, toto, tata).asList());
    }

    /*Grouping items*/
    @Test public void t3() {
        //Group<Person> group = group(meAndMyFriends, by(on(Person.class).getAge()));
        Group1<Integer, Person> group1 = from(meAndMyFriends).groupBy($age);

        //Group<Person> group29aged = group.findGroup("29");
        //Collection<Person> persons29Aged = group.find("29");
        Sequence<Person> group29aged = group1.select(29); //still lazy...

        //assertEquals(2, group29aged.size());
        assertEquals(2, group29aged.asList().size()); //asList to 'eagerize'

        //assertTrue(persons29Aged.contains(titi));
        //assertTrue(persons29Aged.contains(tutu));
        assertEquals(group29aged.asList(), Arrays.asList(titi, tutu));

        //Group<Person> group = group(meAndMyFriends, by(on(Person.class).getAge()), by(on(Person.class).getFirstName()));
        Group2<Integer, String, Person> group2 = from(meAndMyFriends).groupBy($age, $name);

        //Group<Person> group29agedNamedTiti = group29aged.findGroup("Titi");
        final Sequence<Person> group29agedNamedTiti = group2.select(29).select("Titi");
        final Sequence<Person> group29agedNamedTiti_1 = group2.select(29, "Titi");
        assertEquals(group29agedNamedTiti.asList(), Arrays.asList(titi));
    }

    //
    public static class Person {
        private String name;
        private Integer age;

        public Person(String name, int age) { this.name = name; this.age = age; }

        //
        public static final F<Person, String> $name = new F<Person, String>() {
            @Override public String apply(Person person) { return person.name; }
        };
        public static final F<Person, Integer> $age = new F<Person, Integer>() {
            @Override public Integer apply(Person person) { return person.age; }
        };
    }
}
